package core.proto.rightwindow;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.InvalidPropertiesFormatException;
import java.util.List;
import java.util.Properties;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JInternalFrame;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
import javax.swing.text.AbstractDocument;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;

import core.proto.AllComponents;
import core.proto.InfoViz;
import core.proto.Util;
import static app.constants.CollabVizConstants.*;

public class PostIt extends JInternalFrame implements Comparable<PostIt>, ActionListener, KeyListener {

	private static final String OWNERTOKEN = "token";
	private static final String SENDERTOKEN = "sender"; 
	private static final String SESSIONID = "sid";
	private static final String SCREENX = "x";
	private static final String SCREENY = "y";
	private static final String DOCNAME = "docname";
	private static final String USERTEXT = "usertext";
	private static final String UPDATETIME = "lastupdate";

	private JTextArea area; 
	private boolean select;
	private Point origin;
	public static final int SIDE_LENGTH = 200;
	private long timeCreated;
	public static final String DELIMITER = "@=-";

	private Date lastUpdateTime; 

	private String group;
	public BoardPane parent;

	public static final String DATE_FORMAT_NOW = "hh:mm:ss";

	private static long postItId = Long.MIN_VALUE; // The unique postIt id to use for this run. Used to ID the postIt to the other user.  

	private Long sessionId;
	private static Object lock = new Object();

	private Integer ownerToken;		// Unique token of postit creator. 

	private boolean isLocalPostIt; 

	private String docName;	// The name of the document the post it is associated with.  
	private boolean justCreated = true;
	private Point lastScreenLocation;

	private Properties properties; 
	private boolean newlyAddedFromLeftWindow = false;

	private boolean justChangedLocOvetNetwork = false;

	public PostIt(String networkString) {
		Properties p = PostIt.toProperties(networkString);
		init(PostIt.getOwnerToken(p), FOREIGN_NOTE_COLOR, (String) p.get(DOCNAME), Long.valueOf(p.getProperty(SESSIONID)));
	}


	public PostIt(int userToken, boolean newlyAddedFromLeftWindow) {
		String docName = FilenameUtils.getBaseName(AllComponents.getCurrentPath());
		init(userToken, NOTE_COLOR, docName, nextId());
		this.newlyAddedFromLeftWindow = newlyAddedFromLeftWindow;
	}

	private void init(int ownerToken, Color color, String docName, long sid) {
		this.group = BoardPane.INVALID_GROUP;
		this.properties = new Properties();
		this.lastScreenLocation = this.getLocation();
		this.docName = docName;
		this.ownerToken = ownerToken;
		this.isLocalPostIt = this.ownerToken == InfoViz.userToken;
		this.sessionId = sid;
		area = new JTextArea(5,10);
		area.setFocusable(false);
		area.setEnabled(false);
		area.setPreferredSize(new Dimension(120,120));
		area.setIgnoreRepaint(true);
		area.setBackground(color);
		//		area.setFont(new Font("Comic Sans MS", Font.PLAIN, 13));
		area.setBorder(BorderFactory.createLineBorder(Color.black, 2));		
		area.setDragEnabled(true);
		area.setLineWrap(true);
		area.setWrapStyleWord(true);
		area.setMargin(new Insets(5,5,5,5));
		area.setName("PostIt");
		area.setFocusable(true);

		//Set properties of the internal frame holding the post it.
		this.setBounds(0, 0, SIDE_LENGTH, SIDE_LENGTH);
		this.setClosable(false);
		this.setTitle(this.docName);
		this.setResizable(false);
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		this.add(area);
		this.setTimeCreated(System.currentTimeMillis());
		updateTimestamp ();

		//ERIC
		JToolBar toolBar = new JToolBar("Still draggable");
		toolBar.setFloatable(false);
		toolBar.setRollover(true);
		JButton link = new JButton("single");
		link.addActionListener(this);
		JButton linkGroup = new JButton("group");
		linkGroup.addActionListener(this);
		toolBar.add(link, BorderLayout.NORTH);
		toolBar.add(linkGroup, BorderLayout.CENTER);
		this.add(toolBar, BorderLayout.NORTH);
		this.addKeyListener(this);
	}

	public boolean isJustChangedLocOvetNetwork () {
		return justChangedLocOvetNetwork;
	}

	public void setJustChangedLocOvetNetwork (boolean b) {
		justChangedLocOvetNetwork = b;
	}

	public boolean isNewlyAddedFromLeftWindow () {
		return newlyAddedFromLeftWindow;
	}

	public void markNotNewlyAddedFromLeftWindow () {
		newlyAddedFromLeftWindow = false;
	}

	public boolean isJustCreated() {
		return justCreated;
	}

	public void markNotJustCreated () {
		this.justCreated = false;
	}

	private void updateTimestamp () {
		this.lastUpdateTime = Calendar.getInstance().getTime();
	}

	public String getGroup (){
		return group;
	}

	public void setGroup (String group) {
		this.group = group;
	}

	public boolean isLocal () {
		return this.isLocalPostIt;
	}

	private static long nextId () {
		synchronized(lock) {
			return postItId++;
		}
	}

	public long getTimeCreated() {
		return timeCreated;
	}

	public void setTimeCreated(long timeCreated) {
		this.timeCreated = timeCreated;
	}

	public String getText () {
		return area.getText();
	}

	public void setText (String text) {
		area.setText(text);
		this.updateTimestamp();
	}

	public Point getOrigin() {
		return origin;
	}

	public void setOrigin(Point origin) {
		this.origin = origin;
	}

	public JTextArea getArea() {
		return area;
	}

	//Set maximum character limit as maxChars
	public void setMaxCharacterLimit(int maxChars) {
		AbstractDocument pDoc=(AbstractDocument)area.getDocument();
		pDoc.setDocumentFilter(new DocumentSizeFilter(maxChars));
	}


	/** Return true if this node is select. */
	public boolean isSelect() {
		return select;
	}

	/** Mark this node as select. */
	public void setSelect(boolean select) {
		this.select = select;
	}

	/** Collected all the select nodes in list. */
	public static void getSelect(List<PostIt> list, List<PostIt> select) {
		select.clear();
		for (PostIt n : list) {
			if (n.isSelect()) {
				select.add(n);
			}
		}
	}


	/** Select each node in r. */
	public static void selectRect(List<PostIt> list, Rectangle r) {
		for (PostIt n : list) {    	  
			n.setSelect(r.intersects(n.origin.x, n.origin.y, 200, 200));
			if(n.select) {
				n.getArea().setBackground(Color.lightGray);
			}
			else {
				n.restoreNormalColor();
			}
		}
	}

	/** Toggle selected state of each node containing p. */
	public static void selectToggle(List<PostIt> list, Point p) {
		for (PostIt n : list) {
			if (n.contains(p)) {
				n.setSelect(!n.isSelect());
			}
		}
	}



	@Override
	/**
	 * Most recently edited come first.  
	 */
	public int compareTo(PostIt o) {
		return o.lastUpdateTime.compareTo(this.lastUpdateTime);
	}

	public String toNetworkString () throws IOException {
		properties.clear();
		properties.put(SESSIONID, sessionId.toString());
		properties.put(OWNERTOKEN, ownerToken.toString());
		properties.put(SENDERTOKEN, Integer.toString(InfoViz.userToken));
		properties.put(DOCNAME, docName);
		properties.put(SCREENX, Integer.toString(this.getX()));
		properties.put(SCREENY, Integer.toString(this.getY()));
		properties.put(UPDATETIME, this.lastUpdateTime.toString());
		properties.put(USERTEXT, this.getText());
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		properties.store(stream, null);
		return stream.toString(ENCODING);
	}

	/**
	 * @param networkString
	 * @return Properties object containing relevant info, null if malformed. 
	 */
	public static Properties toProperties (String networkString) {
		try{
			Properties properties = new Properties();
			properties.load(IOUtils.toInputStream(networkString));
			return properties;
		} catch (IOException ioe) {
			return null;
		}
	}

	public static int getSenderToken(Properties prop) {
		return Integer.valueOf((String) prop.get(SENDERTOKEN));
	}

	public static int getOwnerToken(Properties prop) {
		return Integer.valueOf((String) prop.get(OWNERTOKEN));
	}

	public static long getSid (Properties prop) {
		return Long.valueOf((String) prop.getProperty(SESSIONID));
	}

	public static String getUniqueKey (Properties prop) {
		return  prop.getProperty(OWNERTOKEN).toString() + prop.getProperty(SESSIONID).toString();
	}

	public static String getMessage (Properties prop) {
		return prop.getProperty(USERTEXT);
	}

	public static Point getLocation (Properties prop) {
		return new Point(Integer.valueOf(prop.get(SCREENX).toString()), Integer.valueOf(prop.get(SCREENY).toString()));
	}

	public void enableTextArea () {
		area.setEnabled(true);
	}

	public void makeEditable () {
		if (this.isLocalPostIt){
			area.requestFocusInWindow();
			area.setEnabled(true);
			area.setEditable(true);
			area.getCaret().setVisible(true);
		}
	}

	public void makeUnEditable () {
		area.setEnabled(false);
		area.setEditable(false);
		area.getCaret().setVisible(false);
		// Update the time stamp. 
		this.updateTimestamp();
	}

	public boolean isEditing () {
		return area.isEditable();
	}

	public void restoreNormalColor () {
		if (this.isLocalPostIt)
			area.setBackground(NOTE_COLOR);
		else
			area.setBackground(FOREIGN_NOTE_COLOR);
	}

	/**
	 * Set the location back to the last screen location. 
	 */
	public void restoreToLastLocation () {
		this.setLocation(lastScreenLocation);
	}

	@Override
	/**
	 * Overridden to remember previous location. 
	 */
	public void setLocation(int x, int y) {
		this.lastScreenLocation = this.getLocation();
		super.setLocation(x,y);
	}

	@Override
	/**
	 * Overridden to remember previous location. 
	 */
	public void setLocation (Point p) {
		this.lastScreenLocation = this.getLocation();
		super.setLocation(p);
	}

	@Override
	/**
	 * Overridden to remember previous location. 
	 */
	public void setBounds (Rectangle r) {
		this.lastScreenLocation = this.getLocation();
		super.setBounds(r);
	}

	@Override
	/**
	 * Overridden to remember previous location. 
	 */
	public void setBounds (int x, int y, int w, int h) {
		this.lastScreenLocation = this.getLocation();
		super.setBounds(x, y, w, h);
	}

	public long getSessionId () {
		return this.sessionId;
	}



	//ERIC
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		System.out.println("single link");

		if(((JButton)e.getSource()).getText().equals("single")){
			BoardPane.singleLink(this);
		}
		else if(((JButton)e.getSource()).getText().equals("group")){
			BoardPane.groupLink(this);
		}
	}


	@Override
	public void keyTyped(KeyEvent e) {

		System.out.println("POSTIT KEY PRESSED");
		
	}


	@Override
	public void keyPressed(KeyEvent e) {

		System.out.println("POSTIT KEY PRESSED");
		
	}


	@Override
	public void keyReleased(KeyEvent e) {
		System.out.println("POSTIT KEY PRESSED");
		
	}
}
